#include "bullet.h"
#include "entity.h"
#include "tag.h"
#include "hitbox.h"
#include "hitpoint.h"
#include "images_diffuse.h"

#include <math.h>

#define bullet_check()\
if(round_end) return 1;\
for_ent(e, ent_all(tagged(self->target_tag)), {\
if(check_hitbox_v(e, parent->position, last)) {\
	remove_hitpoint(e);\
	if(self->on_hit) {\
		self->on_hit(parent->position);\
	}\
	return 1;\
}\
})

extern int round_end;

declare_body(bullet, {
	vec velocity;
	size_t lifetime;
	int target_tag;
	explosion_maker on_hit;
})

declare_tick(bullet, {
	vec last = parent->position;
	parent->position = vadd(parent->position, self->velocity);
	if(--self->lifetime == 0) return 1;
	
	bullet_check();
})

declare_draw(bullet, { })

declare_head(bullet)

declare_body(cycle_center, {
	size_t lifetime;
	vec velocity;
})

declare_tick(cycle_center, {
	parent->position = vadd(parent->position, self->velocity);
	if(--self->lifetime == 0) return 1;
})

declare_draw(cycle_center, { })

declare_head(cycle_center)

declare_body(cycle_bullet, {
	size_t lifetime;
	int target_tag;
	float time;
	entity *center;
	explosion_maker on_hit;
})

declare_tick(cycle_bullet, {
	vec last = parent->position;
	parent->position = vadd(self->center->position, vxy(cos(self->time) * 15, sin(self->time) * 15));
	self->time += 0.2f;
	if(--self->lifetime == 0) return 1;
	
	bullet_check();
})

declare_draw(cycle_bullet, { })

declare_head(cycle_bullet)

declare_body(missile_bullet, {
	vec velocity;
	size_t lifetime;
	int target_tag;
	int children;
	explosion_maker on_hit;
})

declare_tick(missile_bullet, {
	vec last = parent->position;
	parent->position = vadd(parent->position, self->velocity);
	if(--self->lifetime == 0) {
		entity* (*func)(component,vec,vec,explosion_maker);
		func = (self->target_tag == TAG_PLAYER) ? make_enemy_bullet : make_player_bullet;
		sprite *s = (self->target_tag == TAG_PLAYER) ? &sprite_explode_part_bullet : &sprite_player_explode_part;
		for(size_t i = 0; i < self->children; ++i) {
			float t = i * 6.28 / (float)self->children;
			func(
				get_animator_c(s, 2, vxy(3.5f, 3.5f)),
				parent->position,
				vxy(2 * sin(t), 2 * cos(t)),
				self->on_hit
			);
		}
			
		return 1;
	}
	
	bullet_check();
})

declare_draw(missile_bullet, { })

declare_head(missile_bullet)

entity *make_enemy_bullet(component renderer, vec location, vec velocity, explosion_maker em) {
	entity *ent = ent_new();
	ent->position = location;
	ent->tag = TAG_BULLET;
	
	bullet *eb = c_new(bullet);
	eb->velocity = velocity;
	eb->lifetime = 500;
	eb->target_tag = TAG_PLAYER;
	eb->on_hit = em;
	
	add_component(ent, renderer);
	add_component(ent, eb);
	
	return ent;
}

entity *make_player_bullet(component renderer, vec location, vec velocity, explosion_maker em) {
	entity *ent = ent_new();
	ent->position = location;
	ent->tag = TAG_BULLET;
	
	bullet *eb = c_new(bullet);
	eb->velocity = velocity;
	eb->lifetime = 500;
	eb->target_tag = TAG_ENEMY;
	eb->on_hit = em;
	
	add_component(ent, renderer);
	add_component(ent, eb);
	
	return ent;
}

entity *make_cycle_bullet_child(entity *parent, float offset, explosion_maker em, int target_tag, int is_enemy) {
	entity *ent = ent_new();
	ent->tag = TAG_BULLET;
	
	cycle_bullet *cb = c_new(cycle_bullet);
	cb->time = offset;
	cb->on_hit = em;
	cb->target_tag = target_tag;
	cb->center = parent;
	cb->lifetime = 500;
	ent->position = vadd(parent->position, vxy(cos(offset) * 15, sin(offset) * 15));
	
	add_component(ent, get_animator_c(is_enemy ? &sprite_enemy_cycle_bullet : &sprite_cycle_bullet, 3, vxy(2.5f, 2.5f)));
	add_component(ent, cb);
	
	return ent;
}

entity *make_player_cycle_bullet(vec location, vec velocity, explosion_maker em) {
	entity *ent = ent_new();
	ent->position = location;
	ent->tag = TAG_CYCLE_BULLET;
	
	cycle_center *c = c_new(cycle_center);
	c->velocity = velocity;
	c->lifetime = 500;
	//c->target_tag = TAG_ENEMY;
	//c->on_hit = em;
	
	add_component(ent, get_animator_c(&sprite_cycle_center, 2, vxy(5.f, 5.f)));
	add_component(ent, c);
	
	make_cycle_bullet_child(ent, 0, em, TAG_ENEMY, 0);
	make_cycle_bullet_child(ent, 3.14159f/2.f, em, TAG_ENEMY, 0);
	make_cycle_bullet_child(ent, 3.14159f, em, TAG_ENEMY, 0);
	make_cycle_bullet_child(ent, 3.14149f*1.5f, em, TAG_ENEMY, 0);
	
	return ent;
}

entity *make_enemy_cycle_bullet(vec location, vec velocity, explosion_maker em) {
	entity *ent = ent_new();
	ent->position = location;
	ent->tag = TAG_CYCLE_BULLET;
	
	cycle_center *c = c_new(cycle_center);
	c->velocity = velocity;
	c->lifetime = 500;
	//c->target_tag = TAG_ENEMY;
	//c->on_hit = em;
	
	add_component(ent, get_animator_c(&sprite_enemy_cycle_center, 2, vxy(5.f, 5.f)));
	add_component(ent, c);
	
	make_cycle_bullet_child(ent, 0, em, TAG_PLAYER, 1);
	make_cycle_bullet_child(ent, 3.14159f/2.f, em, TAG_PLAYER, 1);
	make_cycle_bullet_child(ent, 3.14159f, em, TAG_PLAYER, 1);
	make_cycle_bullet_child(ent, 3.14149f*1.5f, em, TAG_PLAYER, 1);
	
	return ent;
}

entity *make_enemy_missile_bullet(vec location, vec velocity, explosion_maker em, int children) {
	entity *ent = ent_new();
	ent->position = location;
	ent->tag = TAG_BULLET;
	
	missile_bullet *c = c_new(missile_bullet);
	c->velocity = velocity;
	c->lifetime = 15;
	c->target_tag = TAG_PLAYER;
	c->on_hit = em;
	c->children = children;
	//c->target_tag = TAG_ENEMY;
	//c->on_hit = em;
	
	add_component(ent, get_animator_c(&sprite_explode_bullet, 1, vxy(2.5f, 0.f)));
	add_component(ent, c);
	
	return ent;
}

entity *make_player_missile_bullet(vec location, vec velocity, explosion_maker em, int children) {
	entity *ent = ent_new();
	ent->position = location;
	ent->tag = TAG_BULLET;
	
	missile_bullet *c = c_new(missile_bullet);
	c->velocity = velocity;
	c->lifetime = 15;
	c->target_tag = TAG_ENEMY;
	c->on_hit = em;
	c->children = children;
	//c->target_tag = TAG_ENEMY;
	//c->on_hit = em;
	
	add_component(ent, get_animator_c(&sprite_player_explode_bullet, 1, vxy(2.5f, 0.f)));
	add_component(ent, c);
	
	return ent;
}